//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <elasys_server.h>
#include "CBasicFileSystem.h"

#define FILESYSTEM_CONTROL_CREATE 0
#define FILESYSTEM_CONTROL_DELETE 1

class ktfsdev : public IDeviceDriver
{
public:
    CARAPI_(PInterface) Probe(
         /* [in]  */ REIID riid);

    CARAPI_(UInt32) AddRef(void);

    CARAPI_(UInt32) Release(void);

    CARAPI Aggregate(
        /* [in] */ AggrType aggrType,
        /* [in] */ PInterface pObject);

    CARAPI GetDomain(
         /* [out] */ PInterface *ppObj);

    CARAPI Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Write(
        /* [in] */ Int64 u64Offset,
        /* [in] */ const MemoryBuf & buffer,
        /* [out] */ Int32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf & inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    virtual ~ktfsdev();
    virtual void Dispose();

protected:
    Interlocked     m_cRef;
};

UInt32 ktfsdev::AddRef()
{
    UInt32 nRef = m_cRef.Increment();
    return nRef;
}

UInt32 ktfsdev::Release()
{
    UInt32 nRef = m_cRef.Decrement();

    if (0 == nRef) {
        delete this;
    }
    return nRef;
}

ECode ktfsdev::Aggregate(
    /* [in] */ AggrType aggrType,
    /* [in] */ PInterface pObject)
{
    return E_NOT_IMPLEMENTED;
}

ECode ktfsdev::GetDomain(
    /* [out] */ PInterface *ppObj)
{
    return E_NOT_IMPLEMENTED;
}

PInterface ktfsdev::Probe(
    /* [in]  */ REIID riid)
{
    if (riid == EIID_IInterface) {
        return (IInterface *)(IDeviceDriver *)this;
    }
    else if (riid == EIID_IDeviceDriver) {
        return (IDeviceDriver *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (IInterface *)&ECLSID_CDeviceDriver;
    }
    else if (riid == EIID_INTERFACE_INFO) {
        return (IInterface *)&EIID_IDeviceDriver;
    }

    return NULL;
}

CARAPI ktfsdev::Read(
    /* [in] */ Int64 u64Offset,
    /* [in] */ Int32 bytesToRead,
    /* [out] */ MemoryBuf * pBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return NOERROR;
}

CARAPI ktfsdev::Write(
    /* [in] */ Int64 u64Offset,
    /* [in] */ const MemoryBuf & buffer,
    /* [out] */ Int32 * pBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return NOERROR;
}

ELAPI _CSystem_RegisterRunningObject(
    WString name,
    PInterface pService);
ELAPI _CSystem_FindRunningObject(
    WString name,
    PInterface *ppService);

ELAPI _CSystem_UnregisterRunningObject(
    WString name);

CARAPI ktfsdev::Control(
    /* [in] */ Handle32 nControlCode,
    /* [in] */ const MemoryBuf & inBuffer,
    /* [out] */ MemoryBuf * pOutBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    wchar_t *serviceName = NULL;
    IBasicFileSystem *pIBFS = NULL;
    CKtfsFileSystem *pKtfsFileSystem = NULL;
    ECode ec = NOERROR;

    if (!inBuffer.GetCapacity()) {
        return E_INVALID_ARGUMENT;
    }
    serviceName = (wchar_t *)inBuffer.GetPayload();
    assert(wcslen(serviceName) > 0);

    switch (nControlCode) {
        case FILESYSTEM_CONTROL_CREATE:
            pKtfsFileSystem = new CKtfsFileSystem();
            if (NULL == pKtfsFileSystem) {
                return E_OUT_OF_MEMORY;
            }
            if (NOERROR != (ec = pKtfsFileSystem->Initialize(serviceName))) {
                return ec;
            }

            pIBFS = IBasicFileSystem::Probe((IBasicFileSystem *)pKtfsFileSystem);

            ec = _CSystem_RegisterRunningObject(serviceName, pIBFS);
            if (NOERROR != ec) {
                return ec;
            }
            break;

        case FILESYSTEM_CONTROL_DELETE:
            ec = _CSystem_FindRunningObject(serviceName, (PInterface *)&pIBFS);
            if (NOERROR != ec) {
                return ec;
            }

            ec = _CSystem_UnregisterRunningObject(serviceName);
            if (NOERROR != ec) {
                return ec;
            }

            pIBFS->Release();
            break;

        default:
            break;
    }
    return NOERROR;
}

ktfsdev::~ktfsdev()
{
    assert(0 == m_cRef);
    this->Release();
}

void ktfsdev::Dispose()
{
    delete this;
}

EXTERN IDeviceDriver* CDECL CreateKtfs(uint_t uDeviceNo, void *pvParameter)
{
    ktfsdev *pKtfsDriver = new ktfsdev();
    if (NULL == pKtfsDriver) {
        return NULL;
    }
    pKtfsDriver->AddRef();
    return (IDeviceDriver*)pKtfsDriver;
}

